home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume12 / cnews / part14 < prev    next >
Encoding:
Internet Message Format  |  1987-10-22  |  41.1 KB

  1. Subject:  v12i039:  C News alpha release, Part14/14
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: utzoo!henry (Henry Spencer)
  7. Posting-number: Volume 12, Issue 39
  8. Archive-name: cnews/part14
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 14 (of 14)."
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f 'rna/readnews.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'rna/readnews.c'\"
  20. else
  21. echo shar: Extracting \"'rna/readnews.c'\" \(26200 characters\)
  22. sed "s/^X//" >'rna/readnews.c' <<'END_OF_FILE'
  23. X/*
  24. X * readnews
  25. X *
  26. X *    Michael Rourke (UNSW) April 1984
  27. X */
  28. X
  29. X#include "defs.h"
  30. X
  31. X#define ARTSEP "/"
  32. X
  33. Xchar postnews[]     = POSTNEWS;
  34. Xchar admsub[]     = ADMSUB;
  35. Xchar dfltsub[]     = DFLTSUB;
  36. Xchar *mailpath     = MAIL;
  37. X
  38. X#define    MAXARGV    10        /* used in building argv[]s below */
  39. X
  40. X#ifndef NETID
  41. Xchar systemid[DIRSIZ];
  42. X#else
  43. Xchar systemid[] = NETID;
  44. X#endif
  45. X
  46. Xbool iflag;        /* -i ignore .newsrc */
  47. Xbool lflag;        /* -l print headers only */
  48. Xbool cflag;        /* -c check for news only */
  49. Xbool pflag;        /* -p print everything selected */
  50. Xchar **uflag;        /* -u messagid (unsubscribe from followups) */
  51. Xint usize;        /* number of uflag entries */
  52. Xbool Cflag;        /* -C verbose -c */
  53. Xbool sflag;        /* -s print newsgroup subscription list */
  54. Xbool splus;        /* -s+ */
  55. Xbool slistall;        /* -s? */
  56. Xbool sminus;        /* -s- */
  57. Xchar *sarg;        /* arg to -s[+-] */
  58. Xchar *nflag;        /* -n newsgroups */
  59. Xextern char *rcgrps;    /* -n newsgroups from newsrc file */
  60. Xbool n_on_cline;    /* nflag set on command line */
  61. X
  62. Xextern newsrc    *rc;        /* internal .newsrc */
  63. X
  64. Xactive *alist;        /* internal active list */
  65. X
  66. X#if MANGRPS
  67. Xchar *mangrps;    /* mandatory subsciption list */
  68. X#endif
  69. X
  70. X#if AUSAM
  71. Xstruct pwent pe;        /* current user passwd struct */
  72. Xchar sbuf[SSIZ];    /* passwd strings */
  73. X#else
  74. Xstruct passwd *pp;        /* current user passwd struct */
  75. X#endif
  76. Xlong now;        /* current time */
  77. Xbool interrupt;        /* if interrupt hit */
  78. Xchar *newsdir;        /* %news */
  79. Xuid_t newsuid;        /* %news uid (not used) */
  80. Xbool su;        /* if super user (not used) */
  81. X
  82. Xapplycom list(), check(), commands();
  83. Xvoid *onintr();
  84. Xbool ureject(), seen(), subs(), subsub();
  85. X
  86. X#if MANGRPS
  87. Xchar *getmangrps();
  88. X#endif
  89. X
  90. Xmain(argc, argv)
  91. Xint argc;
  92. Xchar *argv[];
  93. X{
  94. X    char buf[BUFSIZ], *p;
  95. X
  96. X    setbuf(stdout, buf);            /* TODO: remove this? */
  97. X    if (options(--argc, ++argv, true)) {
  98. X        (void) fprintf(stderr, "Usage: readnews [-n newsgroups] [-i] [-clpC] [-s[-+? [group]]] [-u messageid]\n");
  99. X        exit(1);
  100. X    }
  101. X    now = time(&now);
  102. X
  103. X#if AUSAM
  104. X    pe.pw_strings[LNAME] = NEWSROOT;
  105. X    if (getpwuid(&pe, sbuf, sizeof(sbuf)) == PWERROR)
  106. X        error("Password file error.");
  107. X    newsdir = newstr(pe.pw_strings[DIRPATH]);
  108. X    newsuid = pe.pw_limits.l_uid;
  109. X#else
  110. X    if ((pp = getpwnam(NEWSROOT)) == NULL)
  111. X        error("Password file error.");
  112. X    newsdir = newstr(pp->pw_dir);
  113. X    newsuid = pp->pw_uid;
  114. X#endif
  115. X
  116. X#if AUSAM
  117. X#if MANGRPS
  118. X    pe.pw_limits.l_uid = getuid();
  119. X    if (getpwlog(&pe, NIL(char), 0) == PWERROR)    /* want pw_cmask */
  120. X        error("Password file error.");
  121. X#endif
  122. X    pwclose();
  123. X#else
  124. X    pp = NIL(struct passwd );
  125. X    endpwent();
  126. X#endif
  127. X
  128. X#ifndef NETID
  129. X    getaddr(G_SYSNAME, systemid);
  130. X#endif
  131. X
  132. X    if (!iflag)
  133. X        readnewsrc();
  134. X
  135. X    if (nflag)
  136. X        convgrps(nflag);
  137. X    else
  138. X        nflag = dfltsub;
  139. X    if (rcgrps)
  140. X        convgrps(rcgrps);
  141. X    if (!n_on_cline) {
  142. X#if MANGRPS
  143. X        int addsub();
  144. X
  145. X        if (mangrps = getmangrps(pe.pw_cmask))
  146. X            applyng(mangrps, addsub, &nflag);
  147. X#endif
  148. X        if (!ngmatch(admsub, nflag))
  149. X            nflag = newstr3(admsub, NGSEPS, nflag);
  150. X    }
  151. X    if ((int) sflag + (int) lflag + (int) cflag + (int) pflag > 1)
  152. X        error("-clpsC flags are mutually exclusive.");
  153. X    if (uflag)
  154. X        qsort((char *) uflag, (unsigned) usize, sizeof(char *), strpcmp);
  155. X
  156. X    /* user has private mailer? */
  157. X    if ((p = getenv("MAILER")) != NULL)
  158. X        mailpath = newstr(p);
  159. X
  160. X    alist = readactive();
  161. X
  162. X    if (sflag) {
  163. X        if (subs() && !iflag)
  164. X            writenewsrc(alist);
  165. X    } else if (lflag)
  166. X        apply(alist, nflag, list, false);
  167. X    else if (cflag)
  168. X        apply(alist, nflag, check, false);
  169. X    else {
  170. X        if (!pflag) {
  171. X            if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  172. X                (void) signal(SIGINT, onintr);
  173. X            if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  174. X                (void) signal(SIGQUIT, onintr);
  175. X        }
  176. X        apply(alist, nflag, commands, true);
  177. X        if (!iflag)
  178. X            writenewsrc(alist);
  179. X    }
  180. X    exit(0);
  181. X}
  182. X
  183. X#if MANGRPS
  184. X/*
  185. X * make a subscription list of all class groups the user belongs too
  186. X * (mandatory subscription)
  187. X */
  188. Xchar *
  189. Xgetmangrps(cmask)
  190. Xchar *cmask;
  191. X{
  192. X    static char *weekday[] = { 
  193. X        "mon", "tue", "wed", "thu", "fri"     };
  194. X    register char **classes;
  195. X    register char *s, *end;
  196. X    register char *grp;
  197. X    register int i, size;
  198. X    extern char **getclasses();
  199. X
  200. X    grp = NIL(char);
  201. X    if ((classes = getclasses(cmask)) == NIL(char *))
  202. X        error("Can't get classes.");
  203. X    while (*classes) {
  204. X        if (isdigit(**classes)) {
  205. X            /*
  206. X             * trim string after numeric class
  207. X             * if it is a day of the week
  208. X             */
  209. X            s = *classes;
  210. X            while (isdigit(*s) || *s == '.')
  211. X                s++;
  212. X            if (*s) {
  213. X                end = s;
  214. X                while (isalpha(*end))
  215. X                    end++;
  216. X                if (*end && end != s && end - s <= 3) {
  217. X                    size = end - s;
  218. X                    for (i = 0; i < 5; i++)
  219. X                        if (CMPN(s, weekday[i], size) == 0)
  220. X                            break;
  221. X                    if (i != 5)
  222. X                        *s = '\0';
  223. X                }
  224. X            }
  225. X        }
  226. X        grp = (grp? catstr2(grp, ",class.", *classes):
  227. X            newstr2("class.", *classes));
  228. X        classes++;
  229. X    }
  230. X    return grp;
  231. X}
  232. X
  233. X/*
  234. X * if newsgroup "ng" isn't subscribed to, add it to subscription list
  235. X */
  236. Xaddsub(ng, slist)
  237. Xchar *ng;
  238. Xchar **slist;
  239. X{
  240. X    if (!ngmatch(ng, *slist))
  241. X        *slist = newstr3(ng, NGSEPS, *slist);
  242. X}
  243. X
  244. X#endif
  245. X
  246. Xvoid *
  247. Xonintr()
  248. X{
  249. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  250. X        (void) signal(SIGINT, onintr);
  251. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  252. X        (void) signal(SIGQUIT, onintr);
  253. X    interrupt = true;
  254. X}
  255. X
  256. X/*
  257. X * process options
  258. X * can be called from readnewsrc()
  259. X */
  260. Xoptions(argc, argv, cline)
  261. Xint argc;
  262. Xchar *argv[];
  263. Xbool cline;
  264. X{
  265. X    register char c;
  266. X
  267. X    /* TODO: use getopt(3) */
  268. X    while (argc > 0) {
  269. X        if (argv[0][0] != '-')
  270. X            break;
  271. X        while (c = *(++(argv[0]))) {
  272. X            switch (c) {
  273. X            case 'n':
  274. X                if (cline)
  275. X                    nflag = argv[1], n_on_cline = true;
  276. X                else {
  277. X                    if (!n_on_cline)
  278. X                        nflag = (nflag?
  279. X                            catstr2(nflag, NGSEPS, argv[1]):
  280. X                            newstr(argv[1]));
  281. X                    rcgrps = (rcgrps?
  282. X                        catstr2(rcgrps, NGSEPS, argv[1]):
  283. X                        newstr(argv[1]));
  284. X                }
  285. X                argc--, argv++; 
  286. X                break;
  287. X            case 'u':
  288. X                usize++;
  289. X                uflag = (uflag? (char **)myrealloc((char *)uflag,
  290. X                        (int)sizeof(char *) * usize):
  291. X                    (char **)myalloc((int)sizeof(char *)));
  292. X                uflag[usize - 1] = newstr(argv[1]);
  293. X                argc--, argv++; 
  294. X                break;
  295. X            case 'i':
  296. X                iflag = true; 
  297. X                continue;
  298. X            case 's':
  299. X                sflag = true;
  300. X                switch (argv[0][1]) {
  301. X                case '\0':
  302. X                    continue;
  303. X                case '+':
  304. X                    splus = true; 
  305. X                    break;
  306. X                case '?':
  307. X                    slistall = true, ++(argv[0]); 
  308. X                    continue;
  309. X                case '-':
  310. X                    sminus = true; 
  311. X                    break;
  312. X                default:
  313. X                    argc = -1; 
  314. X                    break;
  315. X                }
  316. X                if (argc > 0) {
  317. X                    sarg = newstr(argv[1]);
  318. X                    argc--, argv++;
  319. X                }
  320. X                break;
  321. X            case 'p':
  322. X                pflag = true; 
  323. X                continue;
  324. X            case 'l':
  325. X                lflag = true; 
  326. X                continue;
  327. X            case 'c':
  328. X                cflag = true; 
  329. X                continue;
  330. X            case 'C':
  331. X                cflag = Cflag = true; 
  332. X                continue;
  333. X            default:
  334. X                argc = -1; 
  335. X                break;
  336. X            }
  337. X            break;
  338. X        }
  339. X        argc--, argv++;
  340. X    }
  341. X    return argc != 0;
  342. X}
  343. X
  344. X/*
  345. X * subscription list handling
  346. X * return true if newsrc is to be re-written
  347. X */
  348. Xbool
  349. Xsubs()
  350. X{
  351. X    register newsrc    *np;
  352. X    register active    *ap;
  353. X    register char *tmp, *com;
  354. X    register FILE *f;
  355. X
  356. X    if (slistall) {
  357. X        (void) printf("Active newsgroups:\n");
  358. X        (void) fflush(stdout);
  359. X#ifdef    MC            /* gok. probably a local paginator */
  360. X        com = newstr2("exec ", MC);
  361. X        if ((f = popen(com, "w")) == NULL)
  362. X            f = stdout;
  363. X        free(com);
  364. X#else
  365. X        f = stdout;
  366. X        com = 0;        /* for lint */
  367. X        com = com;        /* for lint */
  368. X#endif
  369. X        for (ap = alist; ap; ap = ap->a_next)
  370. X            (void) fprintf(f, "%s\n", ap->a_name);
  371. X#ifdef    MC
  372. X        if (f != stdout)
  373. X            pclose(f);
  374. X#endif
  375. X        return false;
  376. X    } else if (splus || sminus) {
  377. X        if (strpbrk(sarg, BADGRPCHARS)) {
  378. X            (void) printf("%s: Illegal char in newsgroup.\n", sarg);
  379. X            return false;
  380. X        }
  381. X        if (ngmatch(sarg, nflag)) {
  382. X            /*
  383. X             * normally we subscribe, check for an exclusion
  384. X             */
  385. X            for (np = rc; np; np = np->n_next)
  386. X                if (CMP(sarg, np->n_name) == 0)
  387. X                    break;
  388. X            if (np) {
  389. X                /*
  390. X                 * altering subscribe flag is all
  391. X                 * we need to change
  392. X                 */
  393. X                np->n_subscribe = splus;
  394. X                return true;
  395. X            }
  396. X            if (sminus) {
  397. X                /*
  398. X                 * try deleting from sub list
  399. X                 */
  400. X                if (subsub(sarg, rcgrps))
  401. X                    return true;
  402. X                /*
  403. X                 * add specific exclusion
  404. X                 */
  405. X                rcgrps = newstr4(rcgrps, NGSEPS, NEGS, sarg);
  406. X                return true;
  407. X            }
  408. X        } else if (splus) {
  409. X            /*
  410. X             * we don't subscribe,
  411. X             * try deleting !sarg first
  412. X             */
  413. X            tmp = newstr2(NEGS, sarg);
  414. X            subsub(tmp, rcgrps);
  415. X            if (!ngmatch(sarg, rcgrps))
  416. X                /*
  417. X                 * didn't work, so add explicit subscription
  418. X                 */
  419. X                rcgrps = rcgrps? newstr3(rcgrps, NGSEPS, sarg):
  420. X                    newstr(sarg);
  421. X            return true;
  422. X        }
  423. X    } else {
  424. X        (void) printf("Subscription list: %s", nflag);
  425. X        for (np = rc; np; np = np->n_next)
  426. X            if (!np->n_subscribe && ngmatch(np->n_name, nflag))
  427. X                (void) printf(",!%s", np->n_name);
  428. X        (void) printf("\n");
  429. X    }
  430. X    return false;
  431. X}
  432. X
  433. X
  434. X/*
  435. X * try and delete group from subscription list
  436. X * return true if successful
  437. X */
  438. Xbool
  439. Xsubsub(grp, slist)
  440. Xchar *grp;
  441. Xchar *slist;
  442. X{
  443. X    register char *delim;
  444. X
  445. X    while (*slist) {
  446. X        if (delim = strchr(slist, NGSEPCHAR))
  447. X            *delim = '\0';
  448. X        if (CMP(grp, slist) == 0) {
  449. X            if (delim)
  450. X                (void) strcpy(slist, delim + 1);
  451. X            else if (slist[-1] = ',')
  452. X                slist[-1] = '\0';
  453. X            else
  454. X                slist[0] = '\0';
  455. X            return true;
  456. X        }
  457. X        if (delim)
  458. X            *delim = NGSEPCHAR, slist = delim + 1;
  459. X        else
  460. X            break;
  461. X    }
  462. X    return false;
  463. X}
  464. X
  465. X/*
  466. X * list titles command (-l)
  467. X */
  468. Xapplycom
  469. Xlist(ap, np)
  470. Xactive *ap;
  471. Xnewsrc *np;
  472. X{
  473. X    static active *lastap;
  474. X    static bool first = true;
  475. X    register char *fname;
  476. X    register FILE *f;
  477. X    header h;
  478. X    ino_t ino;
  479. X
  480. X    np->n_last++;
  481. X    fname = convg(newstr5(newsdir, "/", ap->a_name, ARTSEP,
  482. X        itoa(np->n_last)));
  483. X    ino = 0;
  484. X    f = fopen(fname, "r");
  485. X    free(fname);
  486. X    if (!f || seen(f, &ino))
  487. X        return next;
  488. X    gethead(f, &h);
  489. X    if (uflag && h.h_references && ureject(&h)) {
  490. X        freehead(&h);
  491. X        return next;
  492. X    }
  493. X    if (first) {
  494. X        (void) printf("News articles:\n");
  495. X        first = false;
  496. X    }
  497. X    if (lastap != ap)
  498. X        (void) printf("  %s:\n", ap->a_name);
  499. X    lastap = ap;
  500. X    (void) printf("    %-4d %s\n", np->n_last, h.h_subject);
  501. X    (void) fclose(f);
  502. X    freehead(&h);
  503. X    if (ino)
  504. X        seen(NIL(FILE), &ino);
  505. X    return next;
  506. X}
  507. X
  508. X/*
  509. X * check command (-c or -C)
  510. X */
  511. Xapplycom
  512. Xcheck(ap, np)
  513. Xactive *ap;
  514. Xnewsrc *np;
  515. X{
  516. X    static bool done;
  517. X    register int num;
  518. X
  519. X    np->n_last++;
  520. X    if (Cflag) {
  521. X        if (!done)
  522. X            (void) printf("You have news:\n");
  523. X        done = true;
  524. X        num = ap->a_seq - np->n_last + 1;
  525. X        (void) printf("\t%s %d article%s\n", ap->a_name, num, num > 1 ? "s" :
  526. X            "");
  527. X        return nextgroup;
  528. X    } else
  529. X     {
  530. X        (void) printf("You have news.\n");
  531. X        exit(0);
  532. X        /* NOTREACHED */
  533. X    }
  534. X}
  535. X
  536. X
  537. X/*
  538. X * normal command handler (or pflag)
  539. X * commands:
  540. X *
  541. X * \n         print current article
  542. X * +         go to next article
  543. X * q        quit
  544. X * c        cancel
  545. X * r        reply
  546. X * m [person]    mail
  547. X * f         followup
  548. X * p         postnews
  549. X * n [newsgrp]    next newsgroup
  550. X * s [file]    save
  551. X * u        unsubscribe from followup
  552. X * U        unsubscribe from group
  553. X * !stuff    shell escape
  554. X * number or .    go to number
  555. X * -         back to previous article (toggle)
  556. X * x        quick exit
  557. X * h        long header info
  558. X * H        full header
  559. X *
  560. X * inside r, f or p:
  561. X *    .e    edit
  562. X *    .i    interpolate
  563. X *    . or EOT terminate message
  564. X *    .!comd    shell escape
  565. X */
  566. Xapplycom
  567. Xcommands(ap, np, last, pushed)
  568. Xactive *ap;
  569. Xnewsrc *np;
  570. Xbool last;
  571. Xbool pushed;
  572. X{
  573. X    static char errmess[] = "Incorrect command; Type `?' for help.\n";
  574. X    static char form[]    = "%s: %s\n";
  575. X
  576. X    static char savedsys[BUFSIZ / 2];
  577. X    static active    *lastap, *rlastap;
  578. X    static newsrc    lastn;
  579. X    static char number[20];
  580. X    static active    *wantap;
  581. X
  582. X    register char *com, *arg;
  583. X    register int c, i, size;
  584. X    register FILE     *f;
  585. X    char *fname;
  586. X    header        h;
  587. X    newsrc        ntmp;
  588. X    ino_t        ino;
  589. X    bool printed, pheader, verbose, hadinterrupt;
  590. X    applycom    nextact;
  591. X
  592. X    extern char t_from[], t_subject[], t_date[];
  593. X    extern char t_newsgroups[], t_path[], t_sender[];
  594. X    extern char t_replyto[], t_organization[];
  595. X    extern char *strncpy();
  596. X    extern active    *activep();
  597. X
  598. X
  599. X    if (last) {
  600. X        /*
  601. X         * give user one last chance to
  602. X         * see this article
  603. X         */
  604. X        ap = rlastap;
  605. X        np = &lastn;
  606. X        wantap = NIL(active);
  607. X        if (!ap || pflag)
  608. X            return stop;
  609. X    } else if (wantap)
  610. X        /*
  611. X         * doing an "n newsgroup" command
  612. X         */
  613. X        if (wantap != ap)
  614. X            return nextgroup;
  615. X        else
  616. X            wantap = NIL(active);
  617. X
  618. X    fname = convg(newstr5(newsdir, "/", ap->a_name, ARTSEP,
  619. X        itoa(np->n_last + 1)));
  620. X    f = fopen(fname, "r");
  621. X    ino = 0;
  622. X    if (!f || !last && !pushed && seen(f, &ino)) {
  623. X        if (pushed)
  624. X            (void) printf("Article %d (%s) no longer exists.\n",
  625. X                np->n_last + 1, ap->a_name);
  626. X        else
  627. X            np->n_last++;
  628. X        if (f)
  629. X            (void) fclose(f);
  630. X        free(fname);
  631. X        return next;
  632. X    }
  633. X
  634. X    gethead(f, &h);
  635. X    if (!pushed && uflag && h.h_references && ureject(&h)) {
  636. X        /* unsubscribed followup */
  637. X        freehead(&h);
  638. X        np->n_last++;
  639. X        (void) fclose(f);
  640. X        free(fname);
  641. X        return next;
  642. X    }
  643. X
  644. X    (void) printf("\n");
  645. X    interrupt = hadinterrupt = verbose = false;
  646. X    if (last) {
  647. X        (void) printf("No more articles.\n");
  648. X        printed = pheader = true;
  649. X    } else
  650. X        printed = pheader = false;
  651. X
  652. X    while (1) {
  653. X        if (lastap != ap) {
  654. X            size = strlen(ap->a_name) + sizeof("Newsgroup");
  655. X            for (i = 0; i < size; i++)
  656. X                (void) putc('-', stdout);
  657. X            (void) printf("\nNewsgroup %s\n", ap->a_name);
  658. X            for (i = 0; i < size; i++)
  659. X                (void) putc('-', stdout);
  660. X            (void) printf("\n\n");
  661. X        }
  662. X        lastap = ap;
  663. X        if (!pheader) {
  664. X            (void) printf("Article %d of %d (%s)",
  665. X                np->n_last + 1, ap->a_seq, ap->a_name);
  666. X            if (h.h_lines != 0)
  667. X                (void) printf(" (%s lines)", h.h_lines);
  668. X            (void) printf("\n");
  669. X            (void) printf(form, t_subject, h.h_subject);
  670. X            (void) printf(form, t_from, h.h_from);
  671. X            if (verbose || pflag) {
  672. X                (void) printf(form, t_date, h.h_date);
  673. X                (void) printf(form, t_newsgroups, h.h_newsgroups);
  674. X                (void) printf(form, t_path, h.h_path);
  675. X                if (h.h_sender)
  676. X                    (void) printf(form, t_sender, h.h_sender);
  677. X                if (h.h_replyto)
  678. X                    (void) printf(form, t_replyto, h.h_replyto);
  679. X                if (h.h_organisation)
  680. X                    (void) printf(form, t_organization, h.h_organisation);
  681. X                verbose = false;
  682. X            }
  683. X            pheader = true;
  684. X        }
  685. X        if (!pushed && number[0])
  686. X            /*
  687. X             * just returned from a number command
  688. X             * and have another to do
  689. X             */
  690. X            com = number;
  691. X        else if (pflag)
  692. X            /*
  693. X             * just print it
  694. X             */
  695. X            com = "";
  696. X        else
  697. X         {
  698. X            (void) printf("? ");
  699. X            if (fflush(stdout) == EOF) {
  700. X                (void) printf("\n? ");
  701. X                (void) fflush(stdout);
  702. X            }
  703. X            interrupt = false;
  704. X            if ((com = mgets()) == NIL(char)) {
  705. X                if (interrupt)
  706. X                    if (!hadinterrupt) {
  707. X                        clearerr(stdin);
  708. X                        (void) printf("Interrupt\n");
  709. X                        hadinterrupt = true;
  710. X                        interrupt = false;
  711. X                        continue;
  712. X                    }
  713. X                    else
  714. X                        exit(1);
  715. X                nextact = stop;
  716. X                break;
  717. X            }
  718. X            hadinterrupt = false;
  719. X        }
  720. X        if (*com == '!') {
  721. X            if (com[1] == '!') {
  722. X                (void) printf("!%s\n", savedsys);
  723. X                com = savedsys;
  724. X            } else
  725. X                com++;
  726. X            (void) fflush(stdout);
  727. X#ifdef F_SETFD
  728. X            fcntl(fileno(f), F_SETFD, 1);    /* close on exec */
  729. X#endif
  730. X            system(com);
  731. X            if (com != savedsys)
  732. X                strncpy(savedsys, com, sizeof(savedsys) - 1);
  733. X            (void) printf("!\n");
  734. X            if (!printed)
  735. X                pheader = false;
  736. X            continue;
  737. X        }
  738. X        /*
  739. X         * check command syntax
  740. X         */
  741. X        if (*com && !isdigit(*com) && com[1] && (!isspace(com[1]) ||
  742. X            strchr("nsm", *com) == NIL(char))) {
  743. X            (void) printf(errmess);
  744. X            continue;
  745. X        }
  746. X        if (c = *com) {
  747. X            arg = com;
  748. X            while (isspace(*++arg))
  749. X                ;
  750. X        } else
  751. X            arg = NIL(char);
  752. X        switch (c) {
  753. X        case 0:
  754. X        case '.':
  755. X            if (!printed || c == '.') {
  756. X                if (pflag)
  757. X                    (void) printf("\n");
  758. X                print(&h, f);
  759. X                if (pflag) {
  760. X                    nextact = next;
  761. X                    break;
  762. X                }
  763. X                printed = true;
  764. X                continue;
  765. X            }
  766. X        case 'n':            /* B compatible */
  767. X        case '+':
  768. X        case ';':
  769. X            nextact = next;
  770. X            break;
  771. X        case '?':
  772. X            help();
  773. X            continue;
  774. X        case 'c':
  775. X            cancelarticle(&h);
  776. X            continue;
  777. X        case 'r':
  778. X            reply(&h, fname);
  779. X            continue;
  780. X        case 'm':
  781. X            if (!arg || !*arg)
  782. X                (void) printf("Person argument missing.\n");
  783. X            else
  784. X                mail(&h, fname, arg);
  785. X            continue;
  786. X        case 'f':
  787. X            followup(&h, fname);
  788. X            continue;
  789. X        case 'p':
  790. X            pnews(fname);
  791. X            continue;
  792. X        case 'U':
  793. X            if (ngmatch(np->n_name, ADMSUB)
  794. X#if MANGRPS
  795. X             || ngmatch(np->n_name, mangrps))
  796. X#else
  797. X                )
  798. X#endif
  799. X                 {
  800. X                    (void) printf("Group \"%s\" can't be unsubscribed.\n",
  801. X                                              np->n_name);
  802. X                    continue;
  803. X                }
  804. X            np->n_subscribe = false;
  805. X            nextact = nextgroup;
  806. X            break;
  807. X        case 'u':
  808. X            unsubscribe(h.h_references);
  809. X            nextact = next;
  810. X            break;
  811. X        case 'N':            /* B compatible */
  812. X            if (!*arg) {
  813. X                nextact = nextgroup;
  814. X                break;
  815. X            }
  816. X            if ((wantap = activep(arg)) == NIL(active)) {
  817. X                (void) printf("%s: non-existent newsgroup.\n", arg);
  818. X                continue;
  819. X            }
  820. X            if (!ngmatch(arg, nflag)) {
  821. X                (void) printf("%s: is not subscribed to!\n", arg);
  822. X                wantap = NIL(active);
  823. X                continue;
  824. X            }
  825. X            nextact = searchgroup;
  826. X            break;
  827. X        case 's':
  828. X            save(&h, f, arg);
  829. X            continue;
  830. X        case 'q':
  831. X            nextact = stop;
  832. X            break;
  833. X        case 'x':
  834. X            exit(0);
  835. X        case 'h':
  836. X            verbose = true;
  837. X            pheader = false;
  838. X            continue;
  839. X        case 'H':
  840. X            puthead(&h, stdout, printing);
  841. X            continue;
  842. X        case '-':
  843. X            if (pushed) {
  844. X                nextact = next;
  845. X                break;
  846. X            }
  847. X            if (!rlastap || !lastn.n_name) {
  848. X                (void) printf("Can't go back!\n");
  849. X                continue;
  850. X            }
  851. X            nextact = commands(rlastap, &lastn, false, true);
  852. X            /*
  853. X             * number commands, after a "-" act on the
  854. X             * group of the "-" command
  855. X             */
  856. X            while (number[0]) {
  857. X                ntmp = lastn;
  858. X                ntmp.n_last = atoi(number) - 1;
  859. X                number[0] = '\0';
  860. X                nextact = commands(rlastap, &ntmp, false, true);
  861. X            }
  862. X            if (nextact != next)
  863. X                break;
  864. X            (void) printf("\n");
  865. X            pheader = false;
  866. X            continue;
  867. X        default:
  868. X            if (isdigit(c)) {
  869. X                i = c - '0';
  870. X                while (isdigit(*arg))
  871. X                    i = i * 10 + *arg++ - '0';
  872. X            }
  873. X            if (!isdigit(c) || *arg != '\0') {
  874. X                (void) printf(errmess);
  875. X                continue;
  876. X            }
  877. X            number[0] = '\0';
  878. X            if (i < ap->a_low || i > ap->a_seq) {
  879. X                (void) printf("Articles in \"%s\" group range %d to %d.\n",
  880. X                                         np->n_name, ap->a_low, ap->a_seq);
  881. X                continue;
  882. X            }
  883. X            if (pushed) {
  884. X                sprintf(number, "%d", i);
  885. X                nextact = next;
  886. X                break;
  887. X            }
  888. X            ntmp = *np;
  889. X            ntmp.n_last = i - 1;
  890. X            if ((nextact = commands(ap, &ntmp, false, true)) !=
  891. X                next)
  892. X                break;
  893. X            if (!number[0]) {
  894. X                (void) printf("\n");
  895. X                pheader = false;
  896. X            }
  897. X            continue;
  898. X        }
  899. X        break;
  900. X    }
  901. X    rlastap = ap;
  902. X    lastn = *np;
  903. X    if (!pushed && (nextact == next || printed)) {
  904. X        np->n_last++;
  905. X        if (ino)
  906. X            seen(NIL(FILE), &ino);
  907. X    }
  908. X    freehead(&h);
  909. X    (void) fclose(f);
  910. X    free(fname);
  911. X    return nextact;
  912. X}
  913. X
  914. X
  915. X/*
  916. X * see if this is a followup we are ignoring
  917. X */
  918. Xbool
  919. Xureject(hp)
  920. Xregister header *hp;
  921. X{
  922. X    register bool found;
  923. X    register char *rp, *ids, c;
  924. X    char *key[1];
  925. X
  926. X    found = false;
  927. X    rp = hp->h_references;
  928. X    while (*rp && !found) {
  929. X        if (ids = strpbrk(rp, " ,")) {
  930. X            c = *ids;
  931. X            *ids = '\0';
  932. X        }
  933. X        key[0] = rp;
  934. X        found = (bool) (bsearch((char *) key, (char *) uflag, (unsigned) usize,
  935. X             sizeof(char *), strpcmp) != NIL(char));
  936. X        if (ids)
  937. X            *ids = c, rp = ids + 1;
  938. X        else
  939. X            break;
  940. X        while (isspace(*rp) || *rp == ',')
  941. X            rp++;
  942. X    }
  943. X    return found;
  944. X}
  945. X
  946. X
  947. X/*
  948. X * see if the article has links, if so have we seen it?
  949. X * close file if we return true
  950. X *
  951. X * called twice,
  952. X *    first (with f set) to test (and possibly set *ino)
  953. X *    again to put *ino in memory
  954. X */
  955. Xbool
  956. Xseen(f, ino)
  957. XFILE *f;
  958. Xino_t *ino;
  959. X{
  960. X    static int num;
  961. X    static ino_t    *ilist;
  962. X    struct stat statb;
  963. X    register int i;
  964. X
  965. X    if (f) {
  966. X        if (fstat(fileno(f), &statb) != 0 || statb.st_nlink <= 1)
  967. X            return false;
  968. X        for (i = 0; i < num; i++)
  969. X            if (ilist[i] == statb.st_ino) {
  970. X                (void) fclose(f);
  971. X                return true;
  972. X            }
  973. X        *ino = statb.st_ino;
  974. X        return false;
  975. X    } else if (*ino) {
  976. X        num++;
  977. X        ilist = (ino_t * ) (ilist ? myrealloc((char *) ilist, (int) sizeof(ino_t) *
  978. X            num) : myalloc((int) sizeof(ino_t)));
  979. X        ilist[num - 1] = *ino;
  980. X    }
  981. X    return true;
  982. X}
  983. X
  984. X
  985. X/*
  986. X * print out help file
  987. X */
  988. Xhelp()
  989. X{
  990. X    register FILE    *f;
  991. X    register int c;
  992. X    static char helppath[]     = HELP;
  993. X
  994. X    if ((f = fopen(helppath, "r")) == NIL(FILE)) {
  995. X        (void) printf("Can't open %s\n", helppath);
  996. X        return;
  997. X    }
  998. X    while ((c = getc(f)) != EOF)
  999. X        (void) putc(c, stdout);
  1000. X    (void) fclose(f);
  1001. X}
  1002. X
  1003. X/*
  1004. X * cancel an article.
  1005. X * inews does permission checking.
  1006. X */
  1007. Xcancelarticle(hp)
  1008. Xheader *hp;
  1009. X{
  1010. X    char *argv[MAXARGV];
  1011. X
  1012. X    argv[0] = strrchr(postnews, '/') + 1;
  1013. X    argv[1] = "-c";        /* TODO: no such option in C news */
  1014. X    argv[2] = newstr2("cancel ", hp->h_messageid);
  1015. X    argv[3] = "-n";
  1016. X    argv[4] = hp->h_newsgroups;
  1017. X    if (hp->h_distribution) {
  1018. X        argv[5] = "-d";
  1019. X        argv[6] = hp->h_distribution;
  1020. X        argv[7] = NIL(char);
  1021. X    } else
  1022. X        argv[5] = NIL(char);
  1023. X    run(postnews, argv, true);
  1024. X    free(argv[2]);
  1025. X}
  1026. X
  1027. X/*
  1028. X * reply to sender by mail
  1029. X */
  1030. X/* ARGSUSED fname */
  1031. Xreply(hp, fname)
  1032. Xheader *hp;
  1033. Xchar *fname;
  1034. X{
  1035. X    char *argv[MAXARGV];
  1036. X    register int argc;
  1037. X
  1038. X    argc = 0;
  1039. X    argv[argc++] = "mail";
  1040. X#ifdef UNSWMAIL
  1041. X    argv[argc++] = "-s";
  1042. X    if ((argv[argc++] = getsubject(hp)) == NIL(char))
  1043. X        return;
  1044. X    argv[argc++] = "-i";
  1045. X    argv[argc++] = fname;
  1046. X#endif
  1047. X
  1048. X    if ((argv[argc++] = getretaddr(hp)) == NIL(char)) {
  1049. X        (void) printf("Can't work out an address!\n");
  1050. X        return;
  1051. X    }
  1052. X
  1053. X    argv[argc++] = NIL(char);
  1054. X
  1055. X    run(mailpath, argv, false);
  1056. X
  1057. X    free(argv[argc - 2]);
  1058. X}
  1059. X
  1060. X
  1061. X/*
  1062. X * mail to person
  1063. X */
  1064. X/* ARGSUSED hp fname */
  1065. Xmail(hp, fname, person)
  1066. Xheader *hp;
  1067. Xchar *fname, *person;
  1068. X{
  1069. X    char *argv[MAXARGV];
  1070. X    register int argc;
  1071. X
  1072. X    argc = 0;
  1073. X    argv[argc++] = "mail";
  1074. X#ifdef UNSWMAIL
  1075. X    argv[argc++] = "-i";
  1076. X    argv[argc++] = fname;
  1077. X    argv[argc++] = "-s";
  1078. X    argv[argc++] = hp->h_subject;
  1079. X#endif
  1080. X    argv[argc++] = person;
  1081. X    argv[argc++] = NIL(char);
  1082. X
  1083. X    run(mailpath, argv, false);
  1084. X}
  1085. X
  1086. X
  1087. X/*
  1088. X * generate correct headers for a followup article
  1089. X * then call inews.
  1090. X */
  1091. Xfollowup(hp, fname)
  1092. Xheader *hp;
  1093. Xchar *fname;
  1094. X{
  1095. X    register int argc;
  1096. X    char *argv[10];
  1097. X
  1098. X    argc = 0;
  1099. X    argv[argc++] = strrchr(postnews, '/') + 1;
  1100. X    argv[argc++] = "-i";        /* TODO: what's this in B news? */
  1101. X    argv[argc++] = fname;
  1102. X    argv[argc++] = "-r";
  1103. X    if (hp->h_references && hp->h_messageid)
  1104. X        argv[argc++] = newstr3(hp->h_references, " ", hp->h_messageid);
  1105. X    else if (hp->h_messageid)
  1106. X        argv[argc++] = newstr(hp->h_messageid);
  1107. X    else
  1108. X        argc--;
  1109. X
  1110. X    argv[argc++] = "-s";
  1111. X    if ((argv[argc++] = getsubject(hp)) == NIL(char))
  1112. X        return;
  1113. X
  1114. X    argv[argc++] = "-n";
  1115. X    if (hp->h_followupto)
  1116. X        argv[argc++] = hp->h_followupto;
  1117. X    else
  1118. X        argv[argc++] = hp->h_newsgroups;
  1119. X    argv[argc++] = NIL(char);
  1120. X
  1121. X    run(postnews, argv, false);
  1122. X
  1123. X    if (argc == 10)
  1124. X        free(argv[4]);
  1125. X}
  1126. X
  1127. X/*
  1128. X * get correct "Subject: Re: .." line
  1129. X */
  1130. Xchar *
  1131. Xgetsubject(hp)
  1132. Xregister header *hp;
  1133. X{
  1134. X    register char *s;
  1135. X
  1136. X    if (!hp->h_subject) {
  1137. X        (void) printf("Subject: Re: ");
  1138. X        (void) fflush(stdout);
  1139. X        if ((s = mgets()) == NIL(char) || !*s) {
  1140. X            (void) printf("The Subject field is mandatory.\n");
  1141. X            return NIL(char);
  1142. X        }
  1143. X        return newstr2("Re: ", s);
  1144. X    } else if (CMPN(hp->h_subject, "Re: ", 4) != 0 && CMPN(hp->h_subject,
  1145. X         "re: ", 4) != 0)
  1146. X        return newstr2("Re: ", hp->h_subject);
  1147. X    else
  1148. X        return hp->h_subject;
  1149. X}
  1150. X
  1151. X
  1152. X/*
  1153. X * run a command, optionally closing stdin
  1154. X */
  1155. Xrun(com, argv, closein)
  1156. Xchar *com;
  1157. Xchar *argv[];
  1158. Xbool closein;
  1159. X{
  1160. X    int pid, status, r;
  1161. X
  1162. X    switch (pid = fork()) {
  1163. X    default:
  1164. X        /* parent */
  1165. X        break;
  1166. X    case 0:
  1167. X        /* child */
  1168. X        if (closein)
  1169. X            close(fileno(stdin));
  1170. X        execvp(com, argv);
  1171. X        error("can't exec %s", com);
  1172. X        exit(1);
  1173. X
  1174. X    case -1:
  1175. X        error("can't fork");
  1176. X    }
  1177. X
  1178. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1179. X        (void) signal(SIGINT, SIG_IGN);
  1180. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1181. X        (void) signal(SIGQUIT, SIG_IGN);
  1182. X
  1183. X    while ((r = wait(&status)) != pid && r != -1)
  1184. X        ;
  1185. X
  1186. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1187. X        (void) signal(SIGINT, onintr);
  1188. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1189. X        (void) signal(SIGQUIT, onintr);
  1190. X}
  1191. X
  1192. X/*
  1193. X * call postnews
  1194. X */
  1195. Xpnews(fname)
  1196. Xchar *fname;
  1197. X{
  1198. X    char *argv[MAXARGV];
  1199. X
  1200. X    argv[0] = strrchr(postnews, '/') + 1;
  1201. X    argv[1] = "-i";        /* TODO: what's this inews option? */
  1202. X    argv[2] = fname;
  1203. X    argv[3] = NIL(char);
  1204. X    run(postnews, argv, false);
  1205. X}
  1206. X
  1207. X/*
  1208. X * save an article
  1209. X */
  1210. Xsave(hp, f, s)
  1211. Xheader *hp;
  1212. XFILE *f;
  1213. Xchar *s;
  1214. X{
  1215. X    register long pos;
  1216. X    register int c;
  1217. X    register char *cp;
  1218. X    register FILE    *sf;
  1219. X    register char *aname;
  1220. X    long then;
  1221. X    extern char *getenv();
  1222. X
  1223. X    if (!*s) {
  1224. X        if ((aname = getenv("HOME")) == NIL(char)) {
  1225. X            (void) printf("No $HOME in environment.\n");
  1226. X            return;
  1227. X        }
  1228. X        s = aname = newstr3(aname, "/", ARTICLES);
  1229. X    } else
  1230. X        aname = NIL(char);
  1231. X    if ((sf = fopen(s, "a")) == NIL(FILE)) {
  1232. X        (void) fprintf(stderr, "readnews: can't open %s\n", s);
  1233. X        return;
  1234. X    }
  1235. X    if (aname)
  1236. X        free(aname);
  1237. X    pos = ftell(f);
  1238. X    rewind(f);
  1239. X    if (cp = strchr(hp->h_from, ' '))
  1240. X        *cp = '\0';
  1241. X    if (hp->h_date)
  1242. X        then = atot(hp->h_date);
  1243. X    else
  1244. X        then = 0L;
  1245. X    (void) fprintf(sf, "From %s %s", hp->h_from, ctime(then ? &then : &now));
  1246. X    if (cp)
  1247. X        *cp = ' ';
  1248. X    while ((c = getc(f)) != EOF)
  1249. X        (void) putc(c, sf);
  1250. X    (void) fclose(sf);
  1251. X    fseek(f, pos, 0);
  1252. X}
  1253. X
  1254. X
  1255. X/*
  1256. X * unsubscribe from all followup articles
  1257. X * on this topic
  1258. X */
  1259. Xunsubscribe(id)
  1260. Xchar *id;
  1261. X{
  1262. X    register char *s, c;
  1263. X
  1264. X    if (!id || !*id) {
  1265. X        (void) printf("no references! (warning)\n");
  1266. X        return;
  1267. X    }
  1268. X    while (*id) {
  1269. X        if (s = strpbrk(id, " ,")) {
  1270. X            c = *s;
  1271. X            *s = '\0';
  1272. X        }
  1273. X        usize++;
  1274. X        uflag = (uflag ? (char **) myrealloc((char *) uflag, (int) sizeof(char
  1275. X            *) * usize) : (char **) myalloc((int) sizeof(char *)));
  1276. X        uflag[usize - 1] = newstr(id);
  1277. X        if (s)
  1278. X            *s = c, id = s + 1;
  1279. X        else
  1280. X            break;
  1281. X        while (isspace(*id) || *id == ',')
  1282. X            id++;
  1283. X    }
  1284. X    qsort((char *) uflag, (unsigned) usize, sizeof(char *), strpcmp);
  1285. X}
  1286. X
  1287. X
  1288. X/*
  1289. X * print an article, if it's long enough call page()
  1290. X */
  1291. Xprint(hp, f)
  1292. Xheader *hp;
  1293. XFILE *f;
  1294. X{
  1295. X    register int c;
  1296. X    register long pos;
  1297. X
  1298. X    pos = ftell(f);
  1299. X    if (!pflag && hp->h_lines && atoi(hp->h_lines) >= PAGESIZE - 4)
  1300. X        page(f);
  1301. X    else
  1302. X        while ((c = getc(f)) != EOF)
  1303. X            (void) putc(c, stdout);
  1304. X    fseek(f, pos, 0);
  1305. X}
  1306. X
  1307. X
  1308. X/*
  1309. X * copy article text to stdout, and break into pages
  1310. X */
  1311. Xpage(f)
  1312. XFILE *f;
  1313. X{
  1314. X    static char moremess[]     = "<CR for more>";
  1315. X
  1316. X    register int c;
  1317. X    register unsigned lineno;
  1318. X    char lbuf[80];
  1319. X    struct sgttyb ttybuf;
  1320. X
  1321. X    gtty(fileno(stdin), &ttybuf);
  1322. X    if (ttybuf.sg_flags & ECHO) {
  1323. X        ttybuf.sg_flags &= ~ECHO;
  1324. X        stty(fileno(stdin), &ttybuf);
  1325. X        ttybuf.sg_flags |= ECHO;
  1326. X    }
  1327. X    lineno = 1;
  1328. X    while (!interrupt) {
  1329. X        while (lineno < PAGESIZE - 4 && !interrupt) {
  1330. X            while ((c = getc(f)) != EOF && c != '\n')
  1331. X                (void) putc(c, stdout);
  1332. X            if (c == EOF)
  1333. X                goto fastexit;
  1334. X            (void) putc('\n', stdout);
  1335. X            lineno++;
  1336. X        }
  1337. X        if (interrupt)
  1338. X            break;
  1339. X        (void) printf(moremess);
  1340. X        if (fflush(stdout) == EOF)
  1341. X            break;
  1342. X        (void) read(fileno(stdin), lbuf, sizeof(lbuf));    /* TODO: fix */
  1343. X        (void) printf("\r%*s\r", sizeof(moremess), " ");
  1344. X        lineno = 0;
  1345. X    }
  1346. X    if (lineno)
  1347. X        (void) putc('\n', stdout);
  1348. X    interrupt = false;
  1349. Xfastexit:
  1350. X    if (ttybuf.sg_flags & ECHO)
  1351. X        stty(fileno(stdin), &ttybuf);
  1352. X}
  1353. X
  1354. X/* VARARGS1 */
  1355. Xerror(s, a0, a1, a2, a3)
  1356. Xchar *s;
  1357. X{
  1358. X    (void) fprintf(stderr, "readnews: ");
  1359. X    (void) fprintf(stderr, s, a0, a1, a2, a3);
  1360. X    (void) fprintf(stderr, "\n");
  1361. X    exit(1);
  1362. X}
  1363. END_OF_FILE
  1364. if test 26200 -ne `wc -c <'rna/readnews.c'`; then
  1365.     echo shar: \"'rna/readnews.c'\" unpacked with wrong size!
  1366. fi
  1367. # end of 'rna/readnews.c'
  1368. fi
  1369. echo shar: End of archive 14 \(of 14\).
  1370. cp /dev/null ark14isdone
  1371. MISSING=""
  1372. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  1373.     if test ! -f ark${I}isdone ; then
  1374.     MISSING="${MISSING} ${I}"
  1375.     fi
  1376. done
  1377. if test "${MISSING}" = "" ; then
  1378.     echo You have unpacked all 14 archives.
  1379.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1380. else
  1381.     echo You still need to unpack the following archives:
  1382.     echo "        " ${MISSING}
  1383. fi
  1384. if test -f 'rnews/print' -a "${1}" != "-c" ; then 
  1385.   echo shar: Will not clobber existing file \"'rnews/print'\"
  1386. else
  1387. echo shar: Extracting \"'rnews/print'\" \(0 characters\)
  1388. sed "s/^X//" >'rnews/print' <<'END_OF_FILE'
  1389. END_OF_FILE
  1390. if test 0 -ne `wc -c <'rnews/print'`; then
  1391.     echo shar: \"'rnews/print'\" unpacked with wrong size!
  1392. fi
  1393. # end of 'rnews/print'
  1394. fi
  1395. if test -f 'rnews/printc' -a "${1}" != "-c" ; then 
  1396.   echo shar: Will not clobber existing file \"'rnews/printc'\"
  1397. else
  1398. echo shar: Extracting \"'rnews/printc'\" \(0 characters\)
  1399. sed "s/^X//" >'rnews/printc' <<'END_OF_FILE'
  1400. END_OF_FILE
  1401. if test 0 -ne `wc -c <'rnews/printc'`; then
  1402.     echo shar: \"'rnews/printc'\" unpacked with wrong size!
  1403. fi
  1404. # end of 'rnews/printc'
  1405. fi
  1406. if test -f 'rnews/printnonc' -a "${1}" != "-c" ; then 
  1407.   echo shar: Will not clobber existing file \"'rnews/printnonc'\"
  1408. else
  1409. echo shar: Extracting \"'rnews/printnonc'\" \(0 characters\)
  1410. sed "s/^X//" >'rnews/printnonc' <<'END_OF_FILE'
  1411. END_OF_FILE
  1412. if test 0 -ne `wc -c <'rnews/printnonc'`; then
  1413.     echo shar: \"'rnews/printnonc'\" unpacked with wrong size!
  1414. fi
  1415. # end of 'rnews/printnonc'
  1416. fi
  1417. if test -f 'rnews/test/demo/batch.large' -a "${1}" != "-c" ; then 
  1418.   echo shar: Will not clobber existing file \"'rnews/test/demo/batch.large'\"
  1419. else
  1420. echo shar: Extracting \"'rnews/test/demo/batch.large'\" \(0 characters\)
  1421. sed "s/^X//" >'rnews/test/demo/batch.large' <<'END_OF_FILE'
  1422. END_OF_FILE
  1423. if test 0 -ne `wc -c <'rnews/test/demo/batch.large'`; then
  1424.     echo shar: \"'rnews/test/demo/batch.large'\" unpacked with wrong size!
  1425. fi
  1426. # end of 'rnews/test/demo/batch.large'
  1427. fi
  1428. if test -f 'rnews/test/lib/errlog' -a "${1}" != "-c" ; then 
  1429.   echo shar: Will not clobber existing file \"'rnews/test/lib/errlog'\"
  1430. else
  1431. echo shar: Extracting \"'rnews/test/lib/errlog'\" \(0 characters\)
  1432. sed "s/^X//" >'rnews/test/lib/errlog' <<'END_OF_FILE'
  1433. END_OF_FILE
  1434. if test 0 -ne `wc -c <'rnews/test/lib/errlog'`; then
  1435.     echo shar: \"'rnews/test/lib/errlog'\" unpacked with wrong size!
  1436. fi
  1437. # end of 'rnews/test/lib/errlog'
  1438. fi
  1439. if test -f 'rnews/test/lib/history' -a "${1}" != "-c" ; then 
  1440.   echo shar: Will not clobber existing file \"'rnews/test/lib/history'\"
  1441. else
  1442. echo shar: Extracting \"'rnews/test/lib/history'\" \(0 characters\)
  1443. sed "s/^X//" >'rnews/test/lib/history' <<'END_OF_FILE'
  1444. END_OF_FILE
  1445. if test 0 -ne `wc -c <'rnews/test/lib/history'`; then
  1446.     echo shar: \"'rnews/test/lib/history'\" unpacked with wrong size!
  1447. fi
  1448. # end of 'rnews/test/lib/history'
  1449. fi
  1450. if test -f 'rnews/test/lib/history.dir' -a "${1}" != "-c" ; then 
  1451.   echo shar: Will not clobber existing file \"'rnews/test/lib/history.dir'\"
  1452. else
  1453. echo shar: Extracting \"'rnews/test/lib/history.dir'\" \(0 characters\)
  1454. sed "s/^X//" >'rnews/test/lib/history.dir' <<'END_OF_FILE'
  1455. END_OF_FILE
  1456. if test 0 -ne `wc -c <'rnews/test/lib/history.dir'`; then
  1457.     echo shar: \"'rnews/test/lib/history.dir'\" unpacked with wrong size!
  1458. fi
  1459. # end of 'rnews/test/lib/history.dir'
  1460. fi
  1461. if test -f 'rnews/test/lib/history.pag' -a "${1}" != "-c" ; then 
  1462.   echo shar: Will not clobber existing file \"'rnews/test/lib/history.pag'\"
  1463. else
  1464. echo shar: Extracting \"'rnews/test/lib/history.pag'\" \(0 characters\)
  1465. sed "s/^X//" >'rnews/test/lib/history.pag' <<'END_OF_FILE'
  1466. END_OF_FILE
  1467. if test 0 -ne `wc -c <'rnews/test/lib/history.pag'`; then
  1468.     echo shar: \"'rnews/test/lib/history.pag'\" unpacked with wrong size!
  1469. fi
  1470. # end of 'rnews/test/lib/history.pag'
  1471. fi
  1472. if test -f 'rnews/test/lib/log' -a "${1}" != "-c" ; then 
  1473.   echo shar: Will not clobber existing file \"'rnews/test/lib/log'\"
  1474. else
  1475. echo shar: Extracting \"'rnews/test/lib/log'\" \(0 characters\)
  1476. sed "s/^X//" >'rnews/test/lib/log' <<'END_OF_FILE'
  1477. END_OF_FILE
  1478. if test 0 -ne `wc -c <'rnews/test/lib/log'`; then
  1479.     echo shar: \"'rnews/test/lib/log'\" unpacked with wrong size!
  1480. fi
  1481. # end of 'rnews/test/lib/log'
  1482. fi
  1483. if test -f 'rnews/test/lib/realrnews' -a "${1}" != "-c" ; then 
  1484.   echo shar: Will not clobber existing file \"'rnews/test/lib/realrnews'\"
  1485. else
  1486. echo shar: Extracting \"'rnews/test/lib/realrnews'\" \(0 characters\)
  1487. sed "s/^X//" >'rnews/test/lib/realrnews' <<'END_OF_FILE'
  1488. END_OF_FILE
  1489. if test 0 -ne `wc -c <'rnews/test/lib/realrnews'`; then
  1490.     echo shar: \"'rnews/test/lib/realrnews'\" unpacked with wrong size!
  1491. fi
  1492. # end of 'rnews/test/lib/realrnews'
  1493. fi
  1494. if test -f 'rnews/test/time.rnews' -a "${1}" != "-c" ; then 
  1495.   echo shar: Will not clobber existing file \"'rnews/test/time.rnews'\"
  1496. else
  1497. echo shar: Extracting \"'rnews/test/time.rnews'\" \(144 characters\)
  1498. sed "s/^X//" >'rnews/test/time.rnews' <<'END_OF_FILE'
  1499. X#! /bin/sh
  1500. XHERE=`pwd`
  1501. XPATH=$HERE/lib:/bin:/usr/bin; export PATH
  1502. Xtime realrnews -s $HERE/spool -l $HERE/lib <demo/batch.large $* # -d fhlmt # -p
  1503. END_OF_FILE
  1504. if test 144 -ne `wc -c <'rnews/test/time.rnews'`; then
  1505.     echo shar: \"'rnews/test/time.rnews'\" unpacked with wrong size!
  1506. fi
  1507. # end of 'rnews/test/time.rnews'
  1508. fi
  1509. if test -f 'rnews/vers/bsd42/clsexec.c' -a "${1}" != "-c" ; then 
  1510.   echo shar: Will not clobber existing file \"'rnews/vers/bsd42/clsexec.c'\"
  1511. else
  1512. echo shar: Extracting \"'rnews/vers/bsd42/clsexec.c'\" \(158 characters\)
  1513. sed "s/^X//" >'rnews/vers/bsd42/clsexec.c' <<'END_OF_FILE'
  1514. X/*
  1515. X * set close on exec (on Berklix)
  1516. X */
  1517. X
  1518. X#include <stdio.h>
  1519. X#include <sgtty.h>
  1520. X
  1521. Xfclsexec(fp)
  1522. XFILE *fp;
  1523. X{
  1524. X    (void) ioctl(fileno(fp), FIOCLEX, (char *)NULL);
  1525. X}
  1526. END_OF_FILE
  1527. if test 158 -ne `wc -c <'rnews/vers/bsd42/clsexec.c'`; then
  1528.     echo shar: \"'rnews/vers/bsd42/clsexec.c'\" unpacked with wrong size!
  1529. fi
  1530. # end of 'rnews/vers/bsd42/clsexec.c'
  1531. fi
  1532. if test -f 'rnews/vers/bsd42/fcntl.h' -a "${1}" != "-c" ; then 
  1533.   echo shar: Will not clobber existing file \"'rnews/vers/bsd42/fcntl.h'\"
  1534. else
  1535. echo shar: Extracting \"'rnews/vers/bsd42/fcntl.h'\" \(47 characters\)
  1536. sed "s/^X//" >'rnews/vers/bsd42/fcntl.h' <<'END_OF_FILE'
  1537. X#include <sys/file.h>        /* 4.2's O_EXCL defn */
  1538. END_OF_FILE
  1539. if test 47 -ne `wc -c <'rnews/vers/bsd42/fcntl.h'`; then
  1540.     echo shar: \"'rnews/vers/bsd42/fcntl.h'\" unpacked with wrong size!
  1541. fi
  1542. # end of 'rnews/vers/bsd42/fcntl.h'
  1543. fi
  1544. if test -f 'rnews/vers/bsd42/memcpy.c' -a "${1}" != "-c" ; then 
  1545.   echo shar: Will not clobber existing file \"'rnews/vers/bsd42/memcpy.c'\"
  1546. else
  1547. echo shar: Extracting \"'rnews/vers/bsd42/memcpy.c'\" \(84 characters\)
  1548. sed "s/^X//" >'rnews/vers/bsd42/memcpy.c' <<'END_OF_FILE'
  1549. Xmemcpy(to, from, length)
  1550. Xchar *to, *from;
  1551. Xint length;
  1552. X{
  1553. X    bcopy(from, to, length);
  1554. X}
  1555. END_OF_FILE
  1556. if test 84 -ne `wc -c <'rnews/vers/bsd42/memcpy.c'`; then
  1557.     echo shar: \"'rnews/vers/bsd42/memcpy.c'\" unpacked with wrong size!
  1558. fi
  1559. # end of 'rnews/vers/bsd42/memcpy.c'
  1560. fi
  1561. if test -f 'rnews/vers/usg/clsexec.c' -a "${1}" != "-c" ; then 
  1562.   echo shar: Will not clobber existing file \"'rnews/vers/usg/clsexec.c'\"
  1563. else
  1564. echo shar: Extracting \"'rnews/vers/usg/clsexec.c'\" \(145 characters\)
  1565. sed "s/^X//" >'rnews/vers/usg/clsexec.c' <<'END_OF_FILE'
  1566. X/*
  1567. X * set close on exec (on Uglix)
  1568. X */
  1569. X
  1570. X#include <stdio.h>
  1571. X#include <fcntl.h>
  1572. X
  1573. Xfclsexec(fp)
  1574. XFILE *fp;
  1575. X{
  1576. X    (void) fcntl(fileno(fp), F_SETFD, 1);
  1577. X}
  1578. END_OF_FILE
  1579. if test 145 -ne `wc -c <'rnews/vers/usg/clsexec.c'`; then
  1580.     echo shar: \"'rnews/vers/usg/clsexec.c'\" unpacked with wrong size!
  1581. fi
  1582. # end of 'rnews/vers/usg/clsexec.c'
  1583. fi
  1584. if test -f 'rnews/vers/usg/ftime.c' -a "${1}" != "-c" ; then 
  1585.   echo shar: Will not clobber existing file \"'rnews/vers/usg/ftime.c'\"
  1586. else
  1587. echo shar: Extracting \"'rnews/vers/usg/ftime.c'\" \(251 characters\)
  1588. sed "s/^X//" >'rnews/vers/usg/ftime.c' <<'END_OF_FILE'
  1589. X/*
  1590. X * Uglix ftime simulation
  1591. X */
  1592. X
  1593. X#include <sys/types.h>
  1594. X#include <sys/timeb.h>        /* HACK */
  1595. X
  1596. Xftime(tp)
  1597. Xstruct timeb *tp;
  1598. X{
  1599. X    time_t time();
  1600. X
  1601. X    tp->time = time(&tp->time);
  1602. X    tp->millitm = 0;
  1603. X    tp->timezone = 5*60;    /* HACK */
  1604. X    tp->dstflag = 1;    /* HACK */
  1605. X}
  1606. END_OF_FILE
  1607. if test 251 -ne `wc -c <'rnews/vers/usg/ftime.c'`; then
  1608.     echo shar: \"'rnews/vers/usg/ftime.c'\" unpacked with wrong size!
  1609. fi
  1610. # end of 'rnews/vers/usg/ftime.c'
  1611. fi
  1612. if test -f 'rnews/vers/v7/clsexec.c' -a "${1}" != "-c" ; then 
  1613.   echo shar: Will not clobber existing file \"'rnews/vers/v7/clsexec.c'\"
  1614. else
  1615. echo shar: Extracting \"'rnews/vers/v7/clsexec.c'\" \(165 characters\)
  1616. sed "s/^X//" >'rnews/vers/v7/clsexec.c' <<'END_OF_FILE'
  1617. X/*
  1618. X * set close on exec (on Unix)
  1619. X */
  1620. X
  1621. X#include <stdio.h>
  1622. X#include <sgtty.h>
  1623. X
  1624. Xfclsexec(fp)
  1625. XFILE *fp;
  1626. X{
  1627. X    (void) ioctl(fileno(fp), FIOCLEX, (struct sgttyb *)NULL);
  1628. X}
  1629. X
  1630. END_OF_FILE
  1631. if test 165 -ne `wc -c <'rnews/vers/v7/clsexec.c'`; then
  1632.     echo shar: \"'rnews/vers/v7/clsexec.c'\" unpacked with wrong size!
  1633. fi
  1634. # end of 'rnews/vers/v7/clsexec.c'
  1635. fi
  1636. if test -f 'rnews/vers/v7/fcntl.h' -a "${1}" != "-c" ; then 
  1637.   echo shar: Will not clobber existing file \"'rnews/vers/v7/fcntl.h'\"
  1638. else
  1639. echo shar: Extracting \"'rnews/vers/v7/fcntl.h'\" \(0 characters\)
  1640. sed "s/^X//" >'rnews/vers/v7/fcntl.h' <<'END_OF_FILE'
  1641. END_OF_FILE
  1642. if test 0 -ne `wc -c <'rnews/vers/v7/fcntl.h'`; then
  1643.     echo shar: \"'rnews/vers/v7/fcntl.h'\" unpacked with wrong size!
  1644. fi
  1645. # end of 'rnews/vers/v7/fcntl.h'
  1646. fi
  1647. if test -f 'rnews/vers/v8/README' -a "${1}" != "-c" ; then 
  1648.   echo shar: Will not clobber existing file \"'rnews/vers/v8/README'\"
  1649. else
  1650. echo shar: Extracting \"'rnews/vers/v8/README'\" \(85 characters\)
  1651. sed "s/^X//" >'rnews/vers/v8/README' <<'END_OF_FILE'
  1652. XThough it is undocumented, V8 contains an Uglix uname(3) emulation
  1653. Xin the C library.
  1654. END_OF_FILE
  1655. if test 85 -ne `wc -c <'rnews/vers/v8/README'`; then
  1656.     echo shar: \"'rnews/vers/v8/README'\" unpacked with wrong size!
  1657. fi
  1658. # end of 'rnews/vers/v8/README'
  1659. fi
  1660. if test -f 'rnews/zeropad.c' -a "${1}" != "-c" ; then 
  1661.   echo shar: Will not clobber existing file \"'rnews/zeropad.c'\"
  1662. else
  1663. echo shar: Extracting \"'rnews/zeropad.c'\" \(84 characters\)
  1664. sed "s/^X//" >'rnews/zeropad.c' <<'END_OF_FILE'
  1665. X/*
  1666. X * zero-padding printf format(s) (non-broken)
  1667. X */
  1668. X
  1669. Xchar ldzeropad[] = "%0*.*ld";
  1670. END_OF_FILE
  1671. if test 84 -ne `wc -c <'rnews/zeropad.c'`; then
  1672.     echo shar: \"'rnews/zeropad.c'\" unpacked with wrong size!
  1673. fi
  1674. # end of 'rnews/zeropad.c'
  1675. fi
  1676. if test -f 'batch/batchmunch' -a "${1}" != "-c" ; then 
  1677.   echo shar: Will not clobber existing file \"'batch/batchmunch'\"
  1678. else
  1679. echo shar: Extracting \"'batch/batchmunch'\" \(566 characters\)
  1680. sed "s/^X//" >'batch/batchmunch' <<'END_OF_FILE'
  1681. X# Alter batch as appropriate for transmission.  Usually this means doing
  1682. X# data compression.  We explicitly use "-b 12" here because (1) it is the
  1683. X# lowest common denominator for news-capable machines, and (2) higher levels
  1684. X# of -b are much more expensive in time and memory and seldom yield much
  1685. X# denser output.
  1686. X#
  1687. X# Just 'cat' will do if straight pass-through is desired.
  1688. X#
  1689. X# The 'echo' is for compatibility with the stupid 2.11 compressed format.
  1690. X# The 'exec' cuts down the number of processes active for this simple case.
  1691. X
  1692. Xecho '#! cunbatch'
  1693. Xexec compress -b 12
  1694. END_OF_FILE
  1695. if test 566 -ne `wc -c <'batch/batchmunch'`; then
  1696.     echo shar: \"'batch/batchmunch'\" unpacked with wrong size!
  1697. fi
  1698. # end of 'batch/batchmunch'
  1699. fi
  1700. if test -f 'batch/roomfor' -a "${1}" != "-c" ; then 
  1701.   echo shar: Will not clobber existing file \"'batch/roomfor'\"
  1702. else
  1703. echo shar: Extracting \"'batch/roomfor'\" \(649 characters\)
  1704. sed "s/^X//" >'batch/roomfor' <<'END_OF_FILE'
  1705. X# About how many batches of $1 bytes will fit in the available spool space
  1706. X# without cramping things too badly?
  1707. X#
  1708. X# You'll have to change this -- your blocksize, minimum-free-desired amount,
  1709. X# and df output format will probably differ, and your spool area may be on
  1710. X# a different filesystem.
  1711. X
  1712. XPATH=/bin:/usr/bin ; export PATH
  1713. X
  1714. Xmin=15000            # Want to keep this many df blocks free.
  1715. Xblock=512            # Size of df block in bytes.
  1716. Xavail=`df /dev/usr | awk '{print $2}'`        # How much free in spool?
  1717. X
  1718. Xawk "END {
  1719. X    nb = int(($avail - $min) * $block / $1)
  1720. X    if (nb <= 0)
  1721. X        print 0
  1722. X    else if (nb > 50)    # Arbitrary upper bound.
  1723. X        print 50
  1724. X    else
  1725. X        print nb
  1726. X}" /dev/null
  1727. END_OF_FILE
  1728. if test 649 -ne `wc -c <'batch/roomfor'`; then
  1729.     echo shar: \"'batch/roomfor'\" unpacked with wrong size!
  1730. fi
  1731. # end of 'batch/roomfor'
  1732. fi
  1733. if test -f 'expire/histslash.c' -a "${1}" != "-c" ; then 
  1734.   echo shar: Will not clobber existing file \"'expire/histslash.c'\"
  1735. else
  1736. echo shar: Extracting \"'expire/histslash.c'\" \(655 characters\)
  1737. sed "s/^X//" >'expire/histslash.c' <<'END_OF_FILE'
  1738. X/*
  1739. X * Convert slashed filenames to dotted group/article names in a history
  1740. X * file, for use in mkhistory.  Input comes only from stdin.
  1741. X */
  1742. X#include <stdio.h>
  1743. X#include <assert.h>
  1744. X
  1745. Xchar *progname = "histslash";
  1746. X
  1747. Xmain()
  1748. X{
  1749. X    char buf[BUFSIZ];
  1750. X    register char *scan;
  1751. X    register char *last;
  1752. X    extern char *strchr();
  1753. X
  1754. X    while (fgets(buf, BUFSIZ, stdin) != NULL) {
  1755. X        scan = strchr(buf, '\t');
  1756. X        scan = strchr(scan+1, '\t');
  1757. X        scan++;
  1758. X        last = NULL;
  1759. X        while (*scan != '\0') {
  1760. X            if (*scan == '/') {
  1761. X                *scan = '.';
  1762. X                last = scan;
  1763. X            }
  1764. X            if (*scan == ' ' || *scan == '\n') {
  1765. X                assert(last != NULL);
  1766. X                *last = '/';
  1767. X            }
  1768. X            scan++;
  1769. X        }
  1770. X        fputs(buf, stdout);
  1771. X    }
  1772. X}
  1773. END_OF_FILE
  1774. if test 655 -ne `wc -c <'expire/histslash.c'`; then
  1775.     echo shar: \"'expire/histslash.c'\" unpacked with wrong size!
  1776. fi
  1777. # end of 'expire/histslash.c'
  1778. fi
  1779. ##  End of shell archive.
  1780. exit 0
  1781.